home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / TurboTCP 1.0.1 / TurboTCP.source / CTelnetInterpreter.cp < prev    next >
Text File  |  1993-11-21  |  12KB  |  648 lines

  1. /*
  2. ** CTelnetInterpreter.cp
  3. **
  4. **    TurboTCP support library
  5. **    Generic Telnet protocol interpreter
  6. **
  7. **    Copyright © 1993, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11.  
  12. #include "CTelnetInterpreter.h"
  13.  
  14. #include "CTCPDriver.h"
  15. #include "CTCPStream.h"
  16. #include "CTCPResolverCall.h"
  17.  
  18.  
  19. //    —— initialization ——
  20.  
  21. /*______________________________________________________________________
  22. **
  23. ** ITelnetInterpreter
  24. **
  25. **    Initialize the Telnet interpreter session document.
  26. **
  27. **        aSupervisor (CApplication *):    the document’s supervisor
  28. **        printable (Boolean):            TRUE if document is printable
  29. **        recBufferSize (long):        size of the receive buffer we need
  30. **        theDefaultPort (b_16):        default IP port number
  31. **        autoReceiveSize (long):        number of entries in RDS for auto-receive,
  32. **                                    0 to disable autoreceiving
  33. **        autoReceiveNum (short):        number of auto-receive calls to issue at once
  34. **                                    must be at least 1
  35. **
  36. */
  37.  
  38. void CTelnetInterpreter::ITelnetInterpreter (CApplication *aSupervisor, Boolean printable,
  39.                                     long recBufferSize, b_16 theDefaultPort,
  40.                                     short autoReceiveSize, short autoReceiveNum)
  41.  
  42. {
  43.     itsState = normalChar;
  44.     CTCPSessionDoc::ITCPSessionDoc(aSupervisor, printable, recBufferSize, theDefaultPort,
  45.                                 TRUE, autoReceiveSize, autoReceiveNum);
  46.     showFileName = FALSE;
  47. }
  48.  
  49.  
  50. //    —— data handling methods ——
  51.  
  52. /*______________________________________________________________________
  53. **
  54. ** HandleDataArrived
  55. **
  56. **    Process incoming data.
  57. **
  58. **        theData (Ptr):        pointer to the block of data
  59. **        theDataSize (b_16):    size of the data block
  60. **        isUrgent (Boolean):    TRUE if urgent data
  61. **
  62. */
  63.  
  64. void CTelnetInterpreter::HandleDataArrived (Ptr theData, b_16 theDataSize, Boolean isUrgent)
  65.  
  66. {
  67.     uchar    theChar;
  68.     uchar    theLine[83];
  69.     short    lineIndex;
  70.  
  71.  
  72.     // parse each character separately
  73.     
  74.     while (theDataSize--) {
  75.         theChar = (uchar) (*(theData++));
  76.  
  77.  
  78.         // respond to current Telnet state
  79.         
  80.         switch (itsState) {
  81.  
  82.  
  83.             // normal operation: write character
  84.             
  85.             case normalChar:
  86.  
  87.  
  88.                 // optimization: try to grab several chars at once
  89.                 
  90.                 lineIndex = 0;
  91.                 while ((theDataSize > 1) && (theChar >= ' ') && (theChar != charIAC)) {
  92.                     theDataSize++;
  93.                     theData--;
  94.                     lineIndex = 0;
  95.                     while ((theDataSize > 0) && (((uchar) *theData) >= ' ') &&
  96.                                             (*theData != charIAC) && (lineIndex < 80))
  97.                         theDataSize--, theLine[lineIndex++] = (uchar) *(theData++);
  98.                     if ((theDataSize > 0) && (*theData == charCR))
  99.                         theDataSize--, theData++, theLine[lineIndex++] = charCR;
  100.                     if ((theDataSize > 0) && (*theData == charLF))
  101.                         theDataSize--, theData++, theLine[lineIndex++] = charLF;
  102.                     theLine[lineIndex] = '\0';
  103.                     if (lineIndex)
  104.                         HandleNVTLine((char *) &theLine[0]);
  105.                     if (theDataSize < 1)
  106.                         break;
  107.                     theChar = (uchar) (*(theData++));
  108.                     theDataSize--;
  109.                 }
  110.                 
  111.                 if ((lineIndex) && !(theDataSize))
  112.                     break;
  113.  
  114.  
  115.                 // end of loop: test for IAC
  116.                 
  117.                 if (theChar == charIAC) {
  118.                     itsState = gotIAC;
  119.                     if (showDebug)
  120.                         PrintDebugStr("[IAC");
  121.                 }
  122.                 else
  123.                     HandleNVTChar(theChar);
  124.                 break;
  125.  
  126.  
  127.             // received IAC (interpret as command)
  128.             
  129.             case gotIAC:
  130.             case gotIACinSB:
  131.                 ReceivedIAC(theChar);
  132.                 break;
  133.  
  134.  
  135.             // handle other cases
  136.                 
  137.             case gotSB:
  138.                 if (theChar == charIAC) {
  139.                     itsState = gotIACinSB;
  140.                     if (showDebug)
  141.                         PrintDebugStr(" IAC");
  142.                 }
  143.                 else
  144.                     ReceivedSB(theChar);
  145.                 break;
  146.  
  147.             case gotWILL:
  148.                 if (showDebug)
  149.                     PrintDebugCharNum(theChar, ' ', ']');
  150.                 ReceivedWill(theChar);
  151.                 itsState = normalChar;
  152.                 break;
  153.  
  154.             case gotWONT:
  155.                 if (showDebug)
  156.                     PrintDebugCharNum(theChar, ' ', ']');
  157.                 ReceivedWont(theChar);
  158.                 itsState = normalChar;
  159.                 break;
  160.  
  161.             case gotDO:
  162.                 if (showDebug)
  163.                     PrintDebugCharNum(theChar, ' ', ']');
  164.                 ReceivedDo(theChar);
  165.                 itsState = normalChar;
  166.                 break;
  167.  
  168.             case gotDONT:
  169.                 if (showDebug)
  170.                     PrintDebugCharNum(theChar, ' ', ']');
  171.                 ReceivedDont(theChar);
  172.                 itsState = normalChar;
  173.                 break;
  174.         }
  175.     }
  176.  
  177. }
  178.  
  179.  
  180. /*______________________________________________________________________
  181. **
  182. ** HandleNVTChar
  183. **
  184. **    Process a character which was recieved over Telnet for the network virtual terminal.
  185. **
  186. **        theChar (char):    the character which was received
  187. **
  188. */
  189.  
  190. void CTelnetInterpreter::HandleNVTChar (char theChar)
  191.  
  192. {
  193.     // null method
  194. }
  195.  
  196.  
  197. /*______________________________________________________________________
  198. **
  199. ** HandleNVTLine
  200. **
  201. **    Process a line (or <81 chars) which was recieved over Telnet for the network virtual
  202. **    terminal.
  203. **
  204. **        theLine (char *):    the line which was received (C string)
  205. **
  206. */
  207.  
  208. void CTelnetInterpreter::HandleNVTLine (char *theLine)
  209.  
  210. {
  211.     // null method
  212. }
  213.  
  214.  
  215. //    —— Telnet command handling ——
  216.  
  217. /*______________________________________________________________________
  218. **
  219. ** ReceivedIAC
  220. **
  221. **    Respond to a Telnet [IAC command] sequence.
  222. **
  223. **        theCommand (uchar):    the command code
  224. **
  225. */
  226.  
  227. void CTelnetInterpreter::ReceivedIAC (uchar theCommand)
  228.  
  229. {
  230.  
  231.     // which command is it?
  232.  
  233.     switch (theCommand) {
  234.  
  235.         case escSE:
  236.             if (showDebug)
  237.                 PrintDebugStr(" SE]");
  238.             sbBfr[sbBfrIndex] = '\0';
  239.             if (itsState == gotIACinSB)
  240.                 ReceivedSE();
  241.             itsState = normalChar;
  242.             break;
  243.  
  244.         case escNOP:
  245.             if (showDebug)
  246.                 PrintDebugStr(" NOP]");
  247.             itsState = normalChar;
  248.             break;
  249.             
  250.         case escDM:
  251.             if (showDebug)
  252.                 PrintDebugStr(" DM]");
  253.             ReceivedSynch();
  254.             itsState = normalChar;
  255.             break;
  256.             
  257.         case escBRK:
  258.             if (showDebug)
  259.                 PrintDebugStr(" BRK]");
  260.             ReceivedBRK();
  261.             itsState = normalChar;
  262.             break;
  263.             
  264.         case escIP:
  265.             if (showDebug)
  266.                 PrintDebugStr(" IP]");
  267.             ReceivedIP();
  268.             itsState = normalChar;
  269.             break;
  270.             
  271.         case escAO:
  272.             if (showDebug)
  273.                 PrintDebugStr(" AO]");
  274.             ReceivedAO();
  275.             itsState = normalChar;
  276.             break;
  277.             
  278.         case escAYT:
  279.             if (showDebug)
  280.                 PrintDebugStr(" AYT]");
  281.             ReceivedAYT();
  282.             itsState = normalChar;
  283.             break;
  284.             
  285.         case escEC:
  286.             if (showDebug)
  287.                 PrintDebugStr(" EC]");
  288.             ReceivedEC();
  289.             itsState = normalChar;
  290.             break;
  291.             
  292.         case escEL:
  293.             if (showDebug)
  294.                 PrintDebugStr(" EL]");
  295.             ReceivedEL();
  296.             itsState = normalChar;
  297.             break;
  298.             
  299.         case escGA:
  300.             if (showDebug)
  301.                 PrintDebugStr(" GA]");
  302.             ReceivedGA();
  303.             itsState = normalChar;
  304.             break;
  305.             
  306.         case escSB:
  307.             if (showDebug)
  308.                 PrintDebugStr(" SB");
  309.             itsState = gotSB;
  310.             sbBfrIndex = 0;
  311.             break;
  312.         
  313.         case escWILL:
  314.             if (showDebug)
  315.                 PrintDebugStr(" WILL");
  316.             itsState = gotWILL;
  317.             break;
  318.             
  319.         case escWONT:
  320.             if (showDebug)
  321.                 PrintDebugStr(" WONT");
  322.             itsState = gotWONT;
  323.             break;
  324.         
  325.         case escDO:
  326.             if (showDebug)
  327.                 PrintDebugStr(" DO");
  328.             itsState = gotDO;
  329.             break;
  330.         
  331.         case escDONT:
  332.             if (showDebug)
  333.                 PrintDebugStr(" DONT");
  334.             itsState = gotDONT;
  335.             break;
  336.         
  337.         case escIAC:
  338.         default:
  339.             if (itsState == gotIACinSB) {
  340.                 ReceivedSB(theCommand);
  341.                 itsState = gotIAC;
  342.             }
  343.             else {
  344.                 if (showDebug)
  345.                     PrintDebugCharNum(theCommand, '?', ']');
  346.                 HandleNVTChar(theCommand);
  347.                 itsState = normalChar;
  348.             }
  349.     }
  350.  
  351. }
  352.  
  353.  
  354. /*______________________________________________________________________
  355. **
  356. ** ReceivedWill
  357. **
  358. **    Respond to a Telnet [IAC WILL option] sequence.
  359. **
  360. **        theOption (uchar):    the option code
  361. **
  362. */
  363.  
  364. void CTelnetInterpreter::ReceivedWill (uchar theOption)
  365.  
  366. {
  367.     uchar respondStr[4];
  368.  
  369.  
  370.     // reject all options
  371.  
  372.     respondStr[0] = charIAC;
  373.     respondStr[1] = escWONT;
  374.     respondStr[2] = theOption;
  375.     respondStr[3] = '\0';
  376.     if (showDebug) {
  377.         PrintDebugStr("{IAC WONT");
  378.         PrintDebugCharNum(theOption, ' ', '}');
  379.     }
  380.     itsStream->SendCString((char *) &respondStr);
  381. }
  382.  
  383.  
  384. /*______________________________________________________________________
  385. **
  386. ** ReceivedWont
  387. **
  388. **    Respond to a Telnet [IAC WONT option] sequence.
  389. **
  390. **        theOption (uchar):    the option code
  391. **
  392. */
  393.  
  394. void CTelnetInterpreter::ReceivedWont (uchar theOption)
  395.  
  396. {
  397.     // null method
  398. }
  399.  
  400.  
  401. /*______________________________________________________________________
  402. **
  403. ** ReceivedDo
  404. **
  405. **    Respond to a Telnet [IAC DO option] sequence.
  406. **
  407. **        theOption (uChar):    the option code
  408. **
  409. */
  410.  
  411. void CTelnetInterpreter::ReceivedDo (uchar theOption)
  412.  
  413. {
  414.     uchar respondStr[4];
  415.  
  416.  
  417.     // reject all options
  418.     
  419.     respondStr[0] = charIAC;
  420.     respondStr[1] = escWONT;
  421.     respondStr[2] = theOption;
  422.     respondStr[3] = '\0';
  423.     if (showDebug) {
  424.         PrintDebugStr("{IAC WONT");
  425.         PrintDebugCharNum(theOption, ' ', '}');
  426.     }
  427.     itsStream->SendCString((char *) &respondStr);
  428. }
  429.  
  430.  
  431. /*______________________________________________________________________
  432. **
  433. ** ReceivedDont
  434. **
  435. **    Respond to a Telnet [IAC DONT option] sequence.
  436. **
  437. **        theOption (uchar):    the option code
  438. **
  439. */
  440.  
  441. void CTelnetInterpreter::ReceivedDont (uchar theOption)
  442.  
  443. {
  444.     // null method
  445. }
  446.  
  447.  
  448. /*______________________________________________________________________
  449. **
  450. ** ReceivedBRK
  451. **
  452. **    Respond to a Telnet [IAC BRK] sequence.
  453. **
  454. */
  455.  
  456. void CTelnetInterpreter::ReceivedBRK (void)
  457.  
  458. {
  459.     // null method
  460. }
  461.  
  462.  
  463. /*______________________________________________________________________
  464. **
  465. ** ReceivedSynch
  466. **
  467. **    Respond to a Telnet [Urgent][IAC DM] sequence.
  468. **
  469. */
  470.  
  471. void CTelnetInterpreter::ReceivedSynch (void)
  472.  
  473. {
  474.     // null method
  475. }
  476.  
  477.  
  478. /*______________________________________________________________________
  479. **
  480. ** ReceivedIP
  481. **
  482. **    Respond to a Telnet [IAC IP] sequence.
  483. **
  484. */
  485.  
  486. void CTelnetInterpreter::ReceivedIP (void)
  487.  
  488. {
  489.     // null method
  490. }
  491.  
  492.  
  493. /*______________________________________________________________________
  494. **
  495. ** ReceivedAO
  496. **
  497. **    Respond to a Telnet [IAC AO] sequence.
  498. **
  499. */
  500.  
  501. void CTelnetInterpreter::ReceivedAO (void)
  502.  
  503. {
  504.     // null method
  505. }
  506.  
  507.  
  508. /*______________________________________________________________________
  509. **
  510. ** ReceivedAYT
  511. **
  512. **    Respond to a Telnet [IAC AYT] sequence.
  513. **
  514. */
  515.  
  516. void CTelnetInterpreter::ReceivedAYT (void)
  517.  
  518. {
  519.     // null method
  520. }
  521.  
  522.  
  523. /*______________________________________________________________________
  524. **
  525. ** ReceivedEC
  526. **
  527. **    Respond to a Telnet [IAC EC] sequence.
  528. **
  529. */
  530.  
  531. void CTelnetInterpreter::ReceivedEC (void)
  532.  
  533. {
  534.     // null method
  535. }
  536.  
  537.  
  538. /*______________________________________________________________________
  539. **
  540. ** ReceivedEL
  541. **
  542. **    Respond to a Telnet [IAC EL] sequence.
  543. **
  544. */
  545.  
  546. void CTelnetInterpreter::ReceivedEL (void)
  547.  
  548. {
  549.     // null method
  550. }
  551.  
  552.  
  553. /*______________________________________________________________________
  554. **
  555. ** ReceivedGA
  556. **
  557. **    Respond to a Telnet [IAC GA] sequence.
  558. **
  559. */
  560.  
  561. void CTelnetInterpreter::ReceivedGA (void)
  562.  
  563. {
  564.     // null method
  565. }
  566.  
  567.  
  568. /*______________________________________________________________________
  569. **
  570. ** ReceivedSB
  571. **
  572. **    Receive subnegotiation parameters. Buffers characters until SE is received.
  573. **
  574. **        theChar (uchar):    the latest character
  575. **
  576. */
  577.  
  578. void CTelnetInterpreter::ReceivedSB (uchar theChar)
  579.  
  580. {
  581.     if (showDebug)
  582.         PrintDebugCharNum(theChar, ' ', '\0');
  583.     sbBfr[sbBfrIndex++] = theChar;
  584. }
  585.  
  586.  
  587. /*______________________________________________________________________
  588. **
  589. ** ReceivedSE
  590. **
  591. **    Parse subnegotiation parameters. Called when [IAC SE] is received.
  592. **
  593. */
  594.  
  595. void CTelnetInterpreter::ReceivedSE (void)
  596.  
  597. {
  598.     // null method
  599. }
  600.  
  601.  
  602. /*______________________________________________________________________
  603. **
  604. **    —— debugging methods ——
  605. **
  606. **    These methods were useful to me in debugging the implementation of various Telnet
  607. **    options. In a terminal-based method (such as MiniTelnet’s CTelnetTerminal), these
  608. **    should be hooked up to routines that print the relevant data to the display screen.
  609. **
  610. */
  611.  
  612. /*______________________________________________________________________
  613. **
  614. ** PrintDebugStr
  615. **
  616. **    Write a string to the terminal for debugging purposes.
  617. **
  618. **        theDebugStr (char *):    the string to write
  619. **
  620. */
  621.  
  622. void CTelnetInterpreter::PrintDebugStr (char *theDebugStr)
  623.  
  624. {
  625.     // null method, since no terminal is defined
  626. }
  627.  
  628.  
  629. /*______________________________________________________________________
  630. **
  631. ** PrintDebugCharNum
  632. **
  633. **    Print a character number for debugging. Provided as a debugging routine. The number
  634. **    is bracketed by the two characters indicated, i.e. if you call PrintDebugCharNum('!', '[', ']'),
  635. **    you get [33] written to the terminal.
  636. **
  637. **        theChar (char):        the character number to write
  638. **        leftBracket (char):    prefix to character number
  639. **        rightBracket (char):    suffix to character number
  640. **
  641. */
  642.  
  643. void CTelnetInterpreter::PrintDebugCharNum (char theChar, char leftBracket, char rightBracket)
  644.  
  645. {
  646.     // null method, since no terminal is defined
  647. }
  648.